// 版权所有2009年围棋作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 包base64实现RFC4648指定的base64编码。
package base64

import (
	"encoding/binary"
	"io"
	"strconv"
)

/*
 * Encodings
 */

// 编码是基数为64的编码/解码方案，由
// 64个字符的字母表。最常见的编码是“base64”
// 在RFC 4648中定义并在MIME（RFC 2045）和PEM中使用的编码
// （RFC 1421）。RFC 4648还定义了一种替代编码，即
// 用-和u.代替+和/的标准编码。
type Encoding struct {
	encode    [64]byte
	decodeMap [256]byte
	padChar   rune
	strict    bool
}

const (
	StdPadding rune = '=' // 标准填充字符
	NoPadding  rune = -1  // 没有填充物
)

const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

// NewEncoding返回由给定字母表定义的新填充编码，
// 它必须是不包含填充字符的64字节字符串
// 或CR/LF（'\r'，'\n'）。
// 生成的编码使用默认的填充字符（'='），
// 可通过WithPadding更改或禁用。
func NewEncoding(encoder string) *Encoding {
	if len(encoder) != 64 {
		panic("encoding alphabet is not 64-bytes long")
	}
	for i := 0; i < len(encoder); i++ {
		if encoder[i] == '\n' || encoder[i] == '\r' {
			panic("encoding alphabet contains newline character")
		}
	}

	e := new(Encoding)
	e.padChar = StdPadding
	copy(e.encode[:], encoder)

	for i := 0; i < len(e.decodeMap); i++ {
		e.decodeMap[i] = 0xFF
	}
	for i := 0; i < len(encoder); i++ {
		e.decodeMap[encoder[i]] = byte(i)
	}
	return e
}

// WithPadding创建与enc相同的新编码，但
// 使用指定的填充字符，或添加以禁用填充。
// 填充字符不能是“\r”或“\n”，不能是
// 包含在编码的字母表中，并且必须是符文或相等符文
// 在“\xff”下面。
func (enc Encoding) WithPadding(padding rune) *Encoding {
	if padding == '\r' || padding == '\n' || padding > 0xff {
		panic("invalid padding")
	}

	for i := 0; i < len(enc.encode); i++ {
		if rune(enc.encode[i]) == padding {
			panic("padding contained in alphabet")
		}
	}

	enc.padChar = padding
	return &enc
}

// Strict创建与enc相同的新编码，除了
// 严格解码已启用。在此模式下，解码器要求
// 尾随填充位为零，如RFC 4648第3.5节所述。
// None
// 请注意，作为新行字符，输入仍然是可延展的
// （CR和LF）仍然被忽略。
func (enc Encoding) Strict() *Encoding {
	enc.strict = true
	return &enc
}

// StdEncoding是标准的base64编码，如中所定义
// RFC4648。
var StdEncoding = NewEncoding(encodeStd)

// URLEncoding是RFC 4648中定义的备用base64编码。
// 它通常用于URL和文件名中。
var URLEncoding = NewEncoding(encodeURL)

// RawStdEncoding是标准的原始、未添加的base64编码，
// 如RFC 4648第3.2节所定义。
// 这与StdEncoding相同，但省略了填充字符。
var RawStdEncoding = StdEncoding.WithPadding(NoPadding)

// RawURLEncoding是RFC 4648中定义的未添加的备用base64编码。
// 它通常用于URL和文件名中。
// 这与URL编码相同，但省略了填充字符。
var RawURLEncoding = URLEncoding.WithPadding(NoPadding)

/*
 * Encoder
 */

// Encode使用编码enc对src进行编码，写入
// EncodedLen（len（src））字节到dst。
// None
// 编码将输出填充为4字节的倍数，
// 因此编码不适合在单个块上使用
// 一个大数据流。改用NewEncoder（）。
func (enc *Encoding) Encode(dst, src []byte) {
	if len(src) == 0 {
		return
	}
	// enc是一个指针接收器，因此在热
	// 下面的循环表示在每次操作时进行零检查。取消那张零票
	// 在环路外加速编码器。
	_ = enc.encode

	di, si := 0, 0
	n := (len(src) / 3) * 3
	for si < n {
		// 将3x 8位源字节转换为4个字节
		val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])

		dst[di+0] = enc.encode[val>>18&0x3F]
		dst[di+1] = enc.encode[val>>12&0x3F]
		dst[di+2] = enc.encode[val>>6&0x3F]
		dst[di+3] = enc.encode[val&0x3F]

		si += 3
		di += 4
	}

	remain := len(src) - si
	if remain == 0 {
		return
	}
	// 添加剩余的小块
	val := uint(src[si+0]) << 16
	if remain == 2 {
		val |= uint(src[si+1]) << 8
	}

	dst[di+0] = enc.encode[val>>18&0x3F]
	dst[di+1] = enc.encode[val>>12&0x3F]

	switch remain {
	case 2:
		dst[di+2] = enc.encode[val>>6&0x3F]
		if enc.padChar != NoPadding {
			dst[di+3] = byte(enc.padChar)
		}
	case 1:
		if enc.padChar != NoPadding {
			dst[di+2] = byte(enc.padChar)
			dst[di+3] = byte(enc.padChar)
		}
	}
}

// EncodeToString返回src的base64编码。
func (enc *Encoding) EncodeToString(src []byte) string {
	buf := make([]byte, enc.EncodedLen(len(src)))
	enc.Encode(buf, src)
	return string(buf)
}

type encoder struct {
	err  error
	enc  *Encoding
	w    io.Writer
	buf  [3]byte    // 等待编码的缓冲数据
	nbuf int        // 以buf为单位的字节数
	out  [1024]byte // 输出缓冲区
}

func (e *encoder) Write(p []byte) (n int, err error) {
	if e.err != nil {
		return 0, e.err
	}

	// 领先的边缘。
	if e.nbuf > 0 {
		var i int
		for i = 0; i < len(p) && e.nbuf < 3; i++ {
			e.buf[e.nbuf] = p[i]
			e.nbuf++
		}
		n += i
		p = p[i:]
		if e.nbuf < 3 {
			return
		}
		e.enc.Encode(e.out[:], e.buf[:])
		if _, e.err = e.w.Write(e.out[:4]); e.err != nil {
			return n, e.err
		}
		e.nbuf = 0
	}

	// 内部大块。
	for len(p) >= 3 {
		nn := len(e.out) / 4 * 3
		if nn > len(p) {
			nn = len(p)
			nn -= nn % 3
		}
		e.enc.Encode(e.out[:], p[:nn])
		if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
			return n, e.err
		}
		n += nn
		p = p[nn:]
	}

	// 后缘。
	for i := 0; i < len(p); i++ {
		e.buf[i] = p[i]
	}
	e.nbuf = len(p)
	n += len(p)
	return
}

// Close刷新来自编码器的任何挂起输出。
// 调用Close后调用Write是一个错误。
func (e *encoder) Close() error {
	// 如果缓冲区里还有什么东西，把它冲洗掉
	if e.err == nil && e.nbuf > 0 {
		e.enc.Encode(e.out[:], e.buf[:e.nbuf])
		_, e.err = e.w.Write(e.out[:e.enc.EncodedLen(e.nbuf)])
		e.nbuf = 0
	}
	return e.err
}

// NewEncoder返回一个新的base64流编码器。数据写入
// 返回的写入程序将使用enc编码，然后写入w。
// Base64编码在4字节块中运行；完成时
// 写入时，调用方必须关闭返回的编码器以刷新任何
// 部分写入的块。
func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
	return &encoder{enc: enc, w: w}
}

// EncodedLen返回base64编码的长度（字节）
// 长度为n的输入缓冲区。
func (enc *Encoding) EncodedLen(n int) int {
	if enc.padChar == NoPadding {
		return (n*8 + 5) / 6 // 每字符6位时的最小字符数
	}
	return (n + 2) / 3 * 4 // 最小4字符量子，每个3字节
}

/*
 * Decoder
 */

type CorruptInputError int64

func (e CorruptInputError) Error() string {
	return "illegal base64 data at input byte " + strconv.FormatInt(int64(e), 10)
}

// decodeQuantum最多可解码4个base64字节。接收到的参数为
// 目标缓冲区dst、源缓冲区src和
// 源缓冲区si。
// 它返回从src读取的字节数，即写入的字节数
// 到dst，以及错误（如果有）。
func (enc *Encoding) decodeQuantum(dst, src []byte, si int) (nsi, n int, err error) {
	// 使用base64字母表解码quantum
	var dbuf [4]byte
	dlen := 4

	// 将零止回阀提升到回路外部。
	_ = enc.decodeMap

	for j := 0; j < len(dbuf); j++ {
		if len(src) == si {
			switch {
			case j == 0:
				return si, 0, nil
			case j == 1, enc.padChar != NoPadding:
				return si, 0, CorruptInputError(si - j)
			}
			dlen = j
			break
		}
		in := src[si]
		si++

		out := enc.decodeMap[in]
		if out != 0xff {
			dbuf[j] = out
			continue
		}

		if in == '\n' || in == '\r' {
			j--
			continue
		}

		if rune(in) != enc.padChar {
			return si, 0, CorruptInputError(si - 1)
		}

		// 我们已经到了终点，还有填充物
		switch j {
		case 0, 1:
			// 填充不正确
			return si, 0, CorruptInputError(si - 1)
		case 2:
			// 应为“=”，第一个“=”已被使用。
			// 跳过换行符
			for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
				si++
			}
			if si == len(src) {
				// 填充不足
				return si, 0, CorruptInputError(len(src))
			}
			if rune(src[si]) != enc.padChar {
				// 填充不正确
				return si, 0, CorruptInputError(si - 1)
			}

			si++
		}

		// 跳过换行符
		for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
			si++
		}
		if si < len(src) {
			// 拖尾垃圾
			err = CorruptInputError(si)
		}
		dlen = j
		break
	}

	// 将4x 6bit源字节转换为3字节
	val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3])
	dbuf[2], dbuf[1], dbuf[0] = byte(val>>0), byte(val>>8), byte(val>>16)
	switch dlen {
	case 4:
		dst[2] = dbuf[2]
		dbuf[2] = 0
		fallthrough
	case 3:
		dst[1] = dbuf[1]
		if enc.strict && dbuf[2] != 0 {
			return si, 0, CorruptInputError(si - 1)
		}
		dbuf[1] = 0
		fallthrough
	case 2:
		dst[0] = dbuf[0]
		if enc.strict && (dbuf[1] != 0 || dbuf[2] != 0) {
			return si, 0, CorruptInputError(si - 2)
		}
	}

	return si, dlen - 1, err
}

// DecodeString返回由base64字符串s表示的字节。
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
	dbuf := make([]byte, enc.DecodedLen(len(s)))
	n, err := enc.Decode(dbuf, []byte(s))
	return dbuf[:n], err
}

type decoder struct {
	err     error
	readErr error // r.Read错误
	enc     *Encoding
	r       io.Reader
	buf     [1024]byte // 剩余输入
	nbuf    int
	out     []byte // 剩余解码输出
	outbuf  [1024 / 4 * 3]byte
}

func (d *decoder) Read(p []byte) (n int, err error) {
	// 使用上次读取的剩余解码输出。
	if len(d.out) > 0 {
		n = copy(p, d.out)
		d.out = d.out[n:]
		return n, nil
	}

	if d.err != nil {
		return 0, d.err
	}

	// 此代码假定d.r条带支持空格（'\r'和'\n'）。

	// 补充缓冲液。
	for d.nbuf < 4 && d.readErr == nil {
		nn := len(p) / 3 * 4
		if nn < 4 {
			nn = 4
		}
		if nn > len(d.buf) {
			nn = len(d.buf)
		}
		nn, d.readErr = d.r.Read(d.buf[d.nbuf:nn])
		d.nbuf += nn
	}

	if d.nbuf < 4 {
		if d.enc.padChar == NoPadding && d.nbuf > 0 {
			// 解码最后的片段，没有填充。
			var nw int
			nw, d.err = d.enc.Decode(d.outbuf[:], d.buf[:d.nbuf])
			d.nbuf = 0
			d.out = d.outbuf[:nw]
			n = copy(p, d.out)
			d.out = d.out[n:]
			if n > 0 || len(p) == 0 && len(d.out) > 0 {
				return n, nil
			}
			if d.err != nil {
				return 0, d.err
			}
		}
		d.err = d.readErr
		if d.err == io.EOF && d.nbuf > 0 {
			d.err = io.ErrUnexpectedEOF
		}
		return 0, d.err
	}

	// 如果p太小，则将块解码为p或d.out，然后解码为p。
	nr := d.nbuf / 4 * 4
	nw := d.nbuf / 4 * 3
	if nw > len(p) {
		nw, d.err = d.enc.Decode(d.outbuf[:], d.buf[:nr])
		d.out = d.outbuf[:nw]
		n = copy(p, d.out)
		d.out = d.out[n:]
	} else {
		n, d.err = d.enc.Decode(p, d.buf[:nr])
	}
	d.nbuf -= nr
	copy(d.buf[:d.nbuf], d.buf[nr:])
	return n, d.err
}

// Decode使用编码enc对src进行解码。它最多写入
// DecodedLen（len（src））字节到dst，并返回字节数
// 书面的如果src包含无效的base64数据，它将返回
// 成功写入和损坏计算机的字节数。
// 忽略新行字符（\r和\n）。
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
	if len(src) == 0 {
		return 0, nil
	}

	// 将零止回阀提升到回路外部。enc.decodeMap是直接
	// 此函数稍后将用于让编译器知道
	// 接受者不可能是零。
	_ = enc.decodeMap

	si := 0
	for strconv.IntSize >= 64 && len(src)-si >= 8 && len(dst)-n >= 8 {
		src2 := src[si : si+8]
		if dn, ok := assemble64(
			enc.decodeMap[src2[0]],
			enc.decodeMap[src2[1]],
			enc.decodeMap[src2[2]],
			enc.decodeMap[src2[3]],
			enc.decodeMap[src2[4]],
			enc.decodeMap[src2[5]],
			enc.decodeMap[src2[6]],
			enc.decodeMap[src2[7]],
		); ok {
			binary.BigEndian.PutUint64(dst[n:], dn)
			n += 6
			si += 8
		} else {
			var ninc int
			si, ninc, err = enc.decodeQuantum(dst[n:], src, si)
			n += ninc
			if err != nil {
				return n, err
			}
		}
	}

	for len(src)-si >= 4 && len(dst)-n >= 4 {
		src2 := src[si : si+4]
		if dn, ok := assemble32(
			enc.decodeMap[src2[0]],
			enc.decodeMap[src2[1]],
			enc.decodeMap[src2[2]],
			enc.decodeMap[src2[3]],
		); ok {
			binary.BigEndian.PutUint32(dst[n:], dn)
			n += 3
			si += 4
		} else {
			var ninc int
			si, ninc, err = enc.decodeQuantum(dst[n:], src, si)
			n += ninc
			if err != nil {
				return n, err
			}
		}
	}

	for si < len(src) {
		var ninc int
		si, ninc, err = enc.decodeQuantum(dst[n:], src, si)
		n += ninc
		if err != nil {
			return n, err
		}
	}
	return n, err
}

// assemble32将4个base64数字组合成3个字节。
// 每个数字来自解码映射，将为0xff
// 如果它来自无效字符。
func assemble32(n1, n2, n3, n4 byte) (dn uint32, ok bool) {
	// 检查所有数字是否有效。如果其中任何一个是0xff，则其
	// 按位OR将为0xff。
	if n1|n2|n3|n4 == 0xff {
		return 0, false
	}
	return uint32(n1)<<26 |
			uint32(n2)<<20 |
			uint32(n3)<<14 |
			uint32(n4)<<8,
		true
}

// assemble64将8个base64数字组合成6个字节。
// 每个数字来自解码映射，将为0xff
// 如果它来自无效字符。
func assemble64(n1, n2, n3, n4, n5, n6, n7, n8 byte) (dn uint64, ok bool) {
	// 检查所有数字是否有效。如果其中任何一个是0xff，则其
	// 按位OR将为0xff。
	if n1|n2|n3|n4|n5|n6|n7|n8 == 0xff {
		return 0, false
	}
	return uint64(n1)<<58 |
			uint64(n2)<<52 |
			uint64(n3)<<46 |
			uint64(n4)<<40 |
			uint64(n5)<<34 |
			uint64(n6)<<28 |
			uint64(n7)<<22 |
			uint64(n8)<<16,
		true
}

type newlineFilteringReader struct {
	wrapped io.Reader
}

func (r *newlineFilteringReader) Read(p []byte) (int, error) {
	n, err := r.wrapped.Read(p)
	for n > 0 {
		offset := 0
		for i, b := range p[:n] {
			if b != '\r' && b != '\n' {
				if i != offset {
					p[offset] = b
				}
				offset++
			}
		}
		if offset > 0 {
			return offset, err
		}
		// 上一个缓冲区完全空白，请重新读取
		n, err = r.wrapped.Read(p)
	}
	return n, err
}

// NewDecoder构造了一个新的base64流解码器。
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
	return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}

// DecodedLen返回解码数据的最大长度（以字节为单位）
// 对应于n字节的base64编码数据。
func (enc *Encoding) DecodedLen(n int) int {
	if enc.padChar == NoPadding {
		// 未添加的数据可能以2-3个字符的部分块结尾。
		return n * 6 / 8
	}
	// 填充base64的长度应始终为4个字符的倍数。
	return n / 4 * 3
}
